1 //------------------------------------------------------------------------------
2 // <copyright file="exe.cs" company="Microsoft">
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
11 // You must not remove this notice, or any other, from this software.
14 //------------------------------------------------------------------------------
19 using System
.Reflection
.Emit
;
20 using System
.Reflection
;
21 using System
.Collections
;
25 AppDomain appdomain
; // assembly domain
26 AssemblyName appname
; // assembly name
27 AssemblyBuilder appbuild
; // assembly builder
28 ModuleBuilder emodule
; // module builder
29 TypeBuilder eclass
; // current class
30 MethodBuilder emethod
; // current method
35 System
.Diagnostics
.SymbolStore
.ISymbolDocumentWriter srcdoc
; // debug source file
36 bool localsdone
= false; // track if we are now emitting instructions
38 public void initOpcodeHash()
40 opcodehash
= new Hashtable(32); // default initial size
41 opcodehash
["neg"] = OpCodes
.Neg
;
42 opcodehash
["mul"] = OpCodes
.Mul
;
43 opcodehash
["div"] = OpCodes
.Div
;
44 opcodehash
["add"] = OpCodes
.Add
;
45 opcodehash
["sub"] = OpCodes
.Sub
;
46 opcodehash
["not"] = OpCodes
.Not
;
47 opcodehash
["and"] = OpCodes
.And
;
48 opcodehash
["or"] = OpCodes
.Or
;
49 opcodehash
["xor"] = OpCodes
.Xor
;
50 opcodehash
["pop"] = OpCodes
.Pop
;
52 opcodehash
["br"] = OpCodes
.Br
;
53 opcodehash
["beq"] = OpCodes
.Beq
;
54 opcodehash
["bge"] = OpCodes
.Bge
;
55 opcodehash
["ble"] = OpCodes
.Ble
;
56 opcodehash
["blt"] = OpCodes
.Blt
;
57 opcodehash
["bgt"] = OpCodes
.Bgt
;
58 opcodehash
["brtrue"] = OpCodes
.Brtrue
;
59 opcodehash
["brfalse"] = OpCodes
.Brfalse
;
61 opcodehash
["cgt"] = OpCodes
.Cgt
;
62 opcodehash
["clt"] = OpCodes
.Clt
;
63 opcodehash
["ceq"] = OpCodes
.Ceq
;
65 opcodehash
["ldc.i4.-1"] = OpCodes
.Ldc_I4_M1
;
66 opcodehash
["ldc.i4.0"] = OpCodes
.Ldc_I4_0
;
67 opcodehash
["ldc.i4.1"] = OpCodes
.Ldc_I4_1
;
68 opcodehash
["ldc.i4.2"] = OpCodes
.Ldc_I4_2
;
69 opcodehash
["ldc.i4.3"] = OpCodes
.Ldc_I4_3
;
70 opcodehash
["ldc.i4.4"] = OpCodes
.Ldc_I4_4
;
71 opcodehash
["ldc.i4.5"] = OpCodes
.Ldc_I4_5
;
72 opcodehash
["ldc.i4.6"] = OpCodes
.Ldc_I4_6
;
73 opcodehash
["ldc.i4.7"] = OpCodes
.Ldc_I4_7
;
74 opcodehash
["ldc.i4.8"] = OpCodes
.Ldc_I4_8
;
77 public Exe(String name
)
83 AssemblyName
getAssemblyName(string s
)
85 AssemblyName a
= new AssemblyName();
86 a
.Name
= filename
+"_assembly";
90 public void BeginModule(string ifile
)
92 appdomain
= System
.Threading
.Thread
.GetDomain();
93 appname
= getAssemblyName(filename
);
94 appbuild
= appdomain
.DefineDynamicAssembly(appname
,
95 AssemblyBuilderAccess
.Save
,
97 emodule
= appbuild
.DefineDynamicModule(
99 Io
.GetOutputFilename(),
101 Guid g
= System
.Guid
.Empty
;
103 srcdoc
= emodule
.DefineDocument(ifile
, g
, g
, g
);
107 public void EndModule()
111 String s
= Io
.GetOutputFilename();
113 Console
.WriteLine("Saving assembly as "+s
);
117 Io
.ICE(e
.ToString());
121 public void BeginClass(String name
, TypeAttributes access
)
124 eclass
= emodule
.DefineType(name
, access
);
127 public void EndClass()
129 eclass
.CreateType(); // create the class
133 * determine the IL static type
135 Type
ilSType(bool sign
, int type
)
141 case Tok
.T_CHAR
: return Type
.GetType("System.SByte");
142 case Tok
.T_SHORT
: return Type
.GetType("System.Int16");
143 case Tok
.T_DEFTYPE
: return Type
.GetType("System.Int32");
144 case Tok
.T_INT
: return Type
.GetType("System.Int32");
145 case Tok
.T_LONG
: return Type
.GetType("System.Int32");
146 case Tok
.T_FLOAT
: return Type
.GetType("System.Single");
147 case Tok
.T_DOUBLE
: return Type
.GetType("System.Double");
148 case Tok
.T_VOID
: return null;
150 Io
.ICE("Unhandled type " + type
);
158 case Tok
.T_CHAR
: return Type
.GetType("U1");
159 case Tok
.T_SHORT
: return Type
.GetType("U2");
160 case Tok
.T_DEFTYPE
: return Type
.GetType("U4");
161 case Tok
.T_INT
: return Type
.GetType("U4");
162 case Tok
.T_LONG
: return Type
.GetType("U4");
164 Io
.ICE("Unhandled type " + type
);
171 * common routine to construct a signature string for a given varlist item
172 * requires a destination ptr, will return the updated dest ptr
174 private Type
genDataTypeSig(Var e
)
180 if (e
.getSign() == Tok
.T_UNSIGNED
) /* if var is unsigned, put it in sig */
183 Type sig
= ilSType(sign
, e
.getTypeId()); /* get the datatype */
189 int id
= e
.getClassId();
191 Io
.ICE("Load instruction with no variable ptr");
192 if (e
.getLocalToken() != null)
194 // LocalToken lt = (LocalToken) e.getLocalToken();
195 LocalBuilder lt
= (LocalBuilder
) e
.getLocalToken();
196 il
.Emit(OpCodes
.Ldloc
, lt
);
198 else if (e
.getFieldBuilder() != null)
200 FieldBuilder fb
= (FieldBuilder
) e
.getFieldBuilder();
201 if (id
== Tok
.T_STATIC
)
202 il
.Emit(OpCodes
.Ldsfld
, fb
);
204 il
.Emit(OpCodes
.Ldfld
, fb
);
208 int index
= e
.getIndex();
209 if (id
== Tok
.T_PARAM
)
212 il
.Emit(OpCodes
.Ldarg_S
, index
);
214 il
.Emit(OpCodes
.Ldarg
, index
);
216 else if (id
== Tok
.T_AUTO
|| id
== Tok
.T_DEFCLASS
)
219 il
.Emit(OpCodes
.Ldloc_S
, e
.getIndex());
221 il
.Emit(OpCodes
.Ldloc
, e
.getIndex());
224 Io
.ICE("Instruction load of unknown class ("
225 + e
.getClassId()+")");
229 public void Load(IAsm a
)
235 public void Store(IAsm a
)
238 int id
= e
.getClassId();
240 Io
.ICE("Store instruction with no variable ptr");
241 if (e
.getLocalToken() != null)
243 // LocalToken lt = (LocalToken) e.getLocalToken();
244 LocalBuilder lt
= (LocalBuilder
) e
.getLocalToken();
245 il
.Emit(OpCodes
.Stloc
, lt
);
247 else if (e
.getFieldBuilder() != null)
249 FieldBuilder fb
= (FieldBuilder
) e
.getFieldBuilder();
250 if (id
== Tok
.T_STATIC
)
251 il
.Emit(OpCodes
.Stsfld
, fb
);
253 il
.Emit(OpCodes
.Stfld
, fb
);
257 int index
= e
.getIndex();
258 if (id
== Tok
.T_PARAM
)
261 il
.Emit(OpCodes
.Starg_S
, index
);
263 il
.Emit(OpCodes
.Starg
, index
);
265 else if (id
== Tok
.T_AUTO
|| id
== Tok
.T_DEFCLASS
)
266 il
.Emit(OpCodes
.Stloc
, index
);
268 Io
.ICE("Instruction load of unknown class ("
269 + e
.getClassId()+")");
273 public void FuncBegin(IAsm a
)
275 Var func
= a
.getVar();
276 Type funcsig
= genDataTypeSig(a
.getVar()); /* gen return type info */
278 VarList paramlist
= func
.getParams(); /* get any params */
279 Type
[] paramTypes
= null; // in case no params
280 if (paramlist
.Length() > 0)
282 int max
= paramlist
.Length();
283 paramTypes
= new Type
[max
];
284 for (int i
= 0; i
< max
; i
++)
286 Var e
= paramlist
.FindByIndex(i
);
287 paramTypes
[i
] = genDataTypeSig(e
);
291 emethod
= eclass
.DefineMethod(func
.getName(),
292 MethodAttributes
.Static
|MethodAttributes
.Public
,
293 funcsig
, paramTypes
);
294 func
.setMethodBuilder(emethod
); // save the method ref
297 * set the argument symbol info
299 for (int i
= 0; i
< paramlist
.Length(); i
++)
300 emethod
.DefineParameter(i
+1, 0, paramlist
.FindByIndex(i
).getName());
302 il
= emethod
.GetILGenerator(); // create new il generator
304 if (func
.getName().Equals("main")) /* special entry point for main */
305 appbuild
.SetEntryPoint(emethod
);
306 // emodule.SetUserEntryPoint(emethod);
309 * must also re-init the label hashtable for each function
311 labelhash
= new Hashtable();
316 public void Call(IAsm a
)
318 Var func
= a
.getVar();
319 Object o
= func
.getMethodBuilder(); // get previous declared reference
321 Io
.ICE("No previous extern for (" + func
.getName() + ")");
322 MethodBuilder mb
= (MethodBuilder
) o
;
323 // il.Emit(OpCodes.Ldc_I4_0); // push 0 for the "this" ptr
324 // VarList x = func.getParams(); /* get any params */
325 // if (x.Length() > 0)
327 // int max = x.Length();
328 // for (int i = 0; i < max; i++)
330 // Var e = x.FindByIndex(i);
334 il
.Emit(OpCodes
.Call
, mb
); // call the MethodBuilder
337 public void Insn(IAsm a
)
339 Object o
= opcodehash
[a
.getInsn()];
341 Io
.ICE("Instruction opcode (" + a
.getInsn() + ") not found in hash");
345 private Hashtable labelhash
; /* labelname hashtable */
347 * get and/or create IL label
348 * put it in hash for reuse
350 private Object
getILLabel(IAsm a
)
352 String s
= a
.getLabel();
353 Object l
= labelhash
[s
];
356 l
= (Object
) il
.DefineLabel();
362 public void Label(IAsm a
)
364 il
.MarkLabel((Label
) getILLabel(a
));
367 public void Branch(IAsm a
)
369 Object o
= opcodehash
[a
.getInsn()];
371 Io
.ICE("Instruction branch opcode (" + a
.getInsn() + ") not found in hash");
372 il
.Emit((OpCode
) o
, (Label
) getILLabel(a
));
375 public void Ret(IAsm a
)
377 il
.Emit(OpCodes
.Ret
);
380 public void FuncEnd()
383 * fill in the current IL stream for this method
385 // emethod.CreateMethodBody(il);
390 public void LocalVars(VarList v
)
392 int max
= v
.Length();
394 for (int i
= 0; i
< max
; i
++) // loop thru the local params
396 Var e
= v
.FindByIndex(i
); // indexed by number
397 Type et
= genDataTypeSig(e
);
398 // LocalToken t = emethod.DeclareLocal(et);
399 LocalBuilder t
= il
.DeclareLocal(et
);
401 t
.SetLocalSymInfo(e
.getName());
407 public void FieldDef(IAsm a
)
409 Var e
= a
.getVar(); /* get the field var ptr */
410 FieldAttributes attr
= FieldAttributes
.Private
; /* default attributes is private */
412 if (e
.getClassId() == Tok
.T_STATIC
)
413 attr
|= FieldAttributes
.Static
;
415 Type t
= genDataTypeSig(e
); /* gen type info */
417 FieldBuilder f
= eclass
.DefineField(e
.getName(), t
, attr
); // returns token
418 e
.setFieldBuilder((Object
) f
); // store token for later usage
421 public void LoadConst(IAsm a
)
423 int value = Convert
.ToInt32(a
.getInsn());
425 if (value > 127 || value < -128) /* if must use long form */
427 il
.Emit(OpCodes
.Ldc_I4
, value);
429 else if (value > 8 || value < -1) /* if must use medium form */
431 il
.Emit(OpCodes
.Ldc_I4_S
, value);
433 else if (value == -1)
435 il
.Emit(OpCodes
.Ldc_I4_M1
);
437 else /* else use short form */
439 Object o
= opcodehash
["ldc.i4."+a
.getInsn()];
441 Io
.ICE("Could not find opcode for (Ldc_I4_" + a
.getInsn() + ")");
446 public void Comment(IAsm a
)
452 if (a
!= null && il
!= null)
454 if (!IsNextNonInsnGen(a
))
457 // Console.WriteLine("Line ("+a.getCommentLine().ToString()+")="+a.getComment());
458 int l
= a
.getCommentLine();
459 il
.MarkSequencePoint(srcdoc
, l
, 0, l
, 0);
467 * is the next assembler directive an non-instruction generation
469 * this is used to keep marksequencepoint from getting multiple calls
470 * with no intervening instructions, which causes it to work incorrectly
472 private bool IsNextNonInsnGen(IAsm a
)
474 IAsm cur
= a
.getNext();
477 int type
= cur
.getIType();
480 * skip intervening labels
482 while (type
== IAsm
.I_LABEL
)
485 type
= cur
.getIType();
489 * if next is comment then return true
491 if (type
== IAsm
.I_COMMENT
)